---
id: typed-linting
title: Linting with Type Information
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Some typescript-eslint rules utilize the awesome power of TypeScript's type checking APIs to provide much deeper insights into your code.
To tap into TypeScript's additional powers, there are two small changes you need to make to your config file:

<Tabs groupId="eslint-config">
<TabItem value="Flat Config">

1. Add `TypeChecked` to the name of any preset configs you're using, namely `recommended`, `strict`, and `stylistic`.
2. Add `languageOptions.parserOptions` to tell our parser how to find the TSConfig for each source file.

```js title="eslint.config.js"
export default tseslint.config(
  eslint.configs.recommended,
  // Remove this line
  ...tseslint.configs.recommended,
  // Added lines start
  ...tseslint.configs.recommendedTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        project: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  },
  // Added lines end
);
```

:::note
[`import.meta.dirname`](https://nodejs.org/api/esm.html#importmetadirname) is only present for ESM files in Node.js >=20.11.0 / >= 21.2.0.<br />
For CommonJS modules and/or older versions of Node.js, [use `__dirname` or an alternative](https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules).
:::

In more detail:

- `tseslint.configs.recommendedTypeChecked` is another [shared configuration](../users/Shared_Configurations.mdx) we provide. This one contains recommended rules that additionally require type information.
- `parserOptions.project: true` indicates to find the closest `tsconfig.json` for each source file (see [Parser#project](../packages/Parser.mdx#project)).
- `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory (see [Parser#tsconfigRootDir](../packages/Parser.mdx#tsconfigrootdir)).

</TabItem>
<TabItem value="Legacy Config">

1. Add `-type-checked` to the name of any preset configs you're using, namely `recommended`, `strict`, and `stylistic`.
2. Add `parserOptions` to tell our parser how to find the TSConfig for each source file.

```js title=".eslintrc.cjs"
/* eslint-env node */
module.exports = {
  extends: [
    'eslint:recommended',
    // Remove this line
    'plugin:@typescript-eslint/recommended',
    // Add this line
    'plugin:@typescript-eslint/recommended-type-checked',
  ],
  plugins: ['@typescript-eslint'],
  parser: '@typescript-eslint/parser',
  // Added lines start
  parserOptions: {
    project: true,
    tsconfigRootDir: __dirname,
  },
  // Added lines end
  root: true,
};
```

In more detail:

- `plugin:@typescript-eslint/recommended-type-checked` is another [shared configuration](../users/Shared_Configurations.mdx) we provide. This one contains recommended rules that additionally require type information.
- `parserOptions.project: true` indicates to find the closest `tsconfig.json` for each source file (see [Parser#project](../packages/Parser.mdx#project)).
- `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory (see [Parser#tsconfigRootDir](../packages/Parser.mdx#tsconfigrootdir)).

</TabItem>
</Tabs>

:::caution
Your ESLint config file may start receiving a parsing error about type information.
See [our TSConfig inclusion FAQ](../troubleshooting/faqs/General.mdx#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file).
:::

With that done, run the same lint command you ran before.
You may see new rules reporting errors based on type information!

## Shared Configurations

If you enabled the [`strict` shared config](../users/Shared_Configurations.mdx#strict) and/or [`stylistic` shared config](../users/Shared_Configurations.mdx#stylistic) in a previous step, be sure to replace them with [`strictTypeChecked`](../users/Shared_Configurations.mdx#strict-type-checked) and [`stylisticTypeChecked`](../users/Shared_Configurations.mdx#stylistic-type-checked) respectively to add their type-checked rules.

<Tabs groupId="eslint-config">
<TabItem value="Flat Config">

```js title="eslint.config.js"
export default tseslint.config(
  eslint.configs.recommended,
  // Removed lines start
  ...tseslint.configs.strict,
  ...tseslint.configs.stylistic,
  // Removed lines end
  // Added lines start
  ...tseslint.configs.strictTypeChecked,
  ...tseslint.configs.stylisticTypeChecked,
  // Added lines end
  // ...
);
```

</TabItem>
<TabItem value="Legacy Config">

```js title=".eslintrc.cjs"
/* eslint-env node */
module.exports = {
  extends: [
    'eslint:recommended',
    // Removed lines start
    'plugin:@typescript-eslint/strict',
    'plugin:@typescript-eslint/stylistic',
    // Removed lines end
    // Added lines start
    'plugin:@typescript-eslint/strict-type-checked',
    'plugin:@typescript-eslint/stylistic-type-checked',
    // Added lines end
  ],
  // ...
};
```

</TabItem>
</Tabs>

You can read more about the rules provided by typescript-eslint in our [rules docs](/rules) and [shared configurations docs](../users/Shared_Configurations.mdx).

## FAQs

### Can I customize the TSConfig used for typed linting?

The `project` option can be turned on with either:

- `true`: to always use `tsconfig.json`s nearest to source files
- `string | string[]`: any number of glob paths to match TSConfig files relative to `parserOptions.tsconfigRootDir`, or the current working directory if that is not provided

For example, if you use a specific `tsconfig.eslint.json` for linting, you'd specify:

<Tabs groupId="eslint-config">
<TabItem value="Flat Config">

```js title="eslint.config.js"
export default tseslint.config({
  // ...
  languageOptions: {
    parserOptions: {
      project: './tsconfig.eslint.json',
      tsconfigRootDir: import.meta.dirname,
    },
  },
  // ...
});
```

</TabItem>
<TabItem value="Legacy Config">

```js title=".eslintrc.js"
module.exports = {
  // ...
  parserOptions: {
    project: './tsconfig.eslint.json',
    tsconfigRootDir: __dirname,
  },
  // ...
};
```

</TabItem>
</Tabs>

See [the `@typescript-eslint/parser` docs for more details](../packages/Parser.mdx#project).

:::note
If your project is a multi-package monorepo, see [our docs on configuring a monorepo](../troubleshooting/typed-linting/Monorepos.mdx).
:::

### How can I disable type-aware linting for a subset of files?

You can combine ESLint's [overrides](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-based-on-glob-patterns) config in conjunction with our [`disable-type-checked`](../users/Shared_Configurations.mdx#disable-type-checked) config to turn off type-aware linting on specific subsets of files.

<Tabs groupId="eslint-config">
<TabItem value="Flat Config">

```js title="eslint.config.js"
export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.recommendedTypeChecked,
  ...tseslint.configs.stylisticTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        project: true,
      },
    },
  },
  // Added lines start
  {
    files: ['**/*.js'],
    ...tseslint.configs.disableTypeChecked,
  },
  // Added lines end
);
```

</TabItem>
<TabItem value="Legacy Config">

```js title=".eslintrc.js"
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended-type-checked',
    'plugin:@typescript-eslint/stylistic-type-checked',
  ],
  plugins: ['@typescript-eslint'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: true,
    tsconfigRootDir: __dirname,
  },
  root: true,
  // Added lines start
  overrides: [
    {
      files: ['*.js'],
      extends: ['plugin:@typescript-eslint/disable-type-checked'],
    },
  ],
  // Added lines end
};
```

</TabItem>
</Tabs>

:::info
If you use type-aware rules from other plugins, you will need to manually disable these rules or use a premade config they provide to disable them.
:::

### How is performance?

Typed rules come with a catch.
By including `parserOptions.project` in your config, you incur the performance penalty of asking TypeScript to do a build of your project before ESLint can do its linting.
For small projects this takes a negligible amount of time (a few seconds or less); for large projects, it can take longer.

Most of our users do not mind this cost as the power and safety of type-aware static analysis rules is worth the tradeoff.
Additionally, most users primarily consume lint errors via IDE plugins which, through caching, do not suffer the same penalties.
This means that generally they usually only run a complete lint before a push, or via their CI, where the extra time often doesn't matter.

**We strongly recommend you do use type-aware linting**, but the above information is included so that you can make your own, informed decision.

## Troubleshooting

If you're having problems getting this working, please have a look at our [Troubleshooting FAQs](../troubleshooting/faqs/General.mdx).
